import { deepMerge } from "@/utils";
import { dateUtil } from "@/utils/dateUtils";
import { isArray, isNullOrUnDef, isObject } from "@/utils/is";
import { error } from "@/utils/log";
import { ValidateFieldsError } from "async-validator";
import { FormItemProp } from "element-plus/es";
import { uniqBy } from "lodash-es";
import { ComputedRef, Ref, toRaw, unref } from "vue";
import { FormActionType, FormProps, FormSchema } from "../..";
import { dateItemType, handleInputNumberValue } from "../helper";
import { Recordable } from "/#/global";
import { EmitType, Fn } from "/#/index";

interface UseFormActionContext {
  emit: EmitType;
  getProps: ComputedRef<FormProps>;
  getSchema: ComputedRef<FormSchema[]>;
  formModel: Recordable;
  defaultValueRef: Ref<Recordable>;
  formElRef: Ref<FormActionType>;
  schemaRef: Ref<FormSchema[]>;
  handleFormValues: Fn;
}

export function useFormEvents({
  emit,
  getProps,
  formModel,
  getSchema,
  defaultValueRef,
  formElRef,
  schemaRef,
  handleFormValues,
}: UseFormActionContext) {
  function getFieldsValue(): Recordable {
    const formEl = unref(formElRef);
    if (!formEl) return {};
    console.log(unref(formModel));
    return handleFormValues(toRaw(unref(formModel)));
  }

  /**
   * @description: Is it time
   */
  function itemIsDateType(key: string) {
    return unref(getSchema).some((item) => {
      return item.field === key ? dateItemType.includes(item.component) : false;
    });
  }

  async function setFieldsValue(values: Recordable): Promise<void> {
    const fields = unref(getSchema)
      .map((item) => item.field)
      .filter(Boolean);

    const validKeys: string[] = [];
    Object.keys(values).forEach((key) => {
      const schema = unref(getSchema).find((item) => item.field === key);
      let value = values[key];

      const hasKey = Reflect.has(values, key);

      // 如果组件是需要数字，转换数字
      value = handleInputNumberValue(schema?.component, value);
      // 0| '' is allow
      if (hasKey && fields.includes(key)) {
        // time type
        if (itemIsDateType(key)) {
          if (Array.isArray(value)) {
            const arr: any[] = [];
            for (const ele of value) {
              arr.push(ele ? dateUtil(ele) : null);
            }
            formModel[key] = arr;
          } else {
            const { componentProps } = schema || {};
            let _props = componentProps as any;
            if (typeof componentProps === "function") {
              _props = _props({ formModel });
            }
            formModel[key] = value
              ? _props?.valueFormat
                ? value
                : dateUtil(value)
              : null;
            console.log(_props?.valueFormat);
          }
        } else {
          formModel[key] = value;
        }
        validKeys.push(key);
      }
    });
    console.log(formModel);
    validateField(validKeys).catch((_) => { });
  }

  async function resetSchema(
    data: Partial<FormSchema> | Partial<FormSchema>[]
  ) {
    console.log(data);
    let updateData: Partial<FormSchema>[] = [];
    if (isObject(data)) {
      updateData.push(data as FormSchema);
    }
    if (isArray(data)) {
      updateData = [...data];
    }

    const hasField = updateData.every(
      (item) =>
        item.component === "ElDivider" ||
        (Reflect.has(item, "field") && item.field)
    );

    if (!hasField) {
      error(
        "All children of the form Schema array that need to be updated must contain the `field` field"
      );
      return;
    }
    schemaRef.value = updateData as FormSchema[];
  }

  async function validateField(
    props?: Array<FormItemProp>,
    callback?: (isValid: boolean, invalidFields?: ValidateFieldsError) => void
  ) {
    return unref(formElRef)?.validateField(props, callback);
  }

  async function validate(
    callback?: (isValid: boolean, invalidFields?: ValidateFieldsError) => void
  ): Promise<any> {
    await unref(formElRef)?.validate(callback);
    return formModel;
  }

  async function resetFields() {
    unref(formElRef).resetFields();
  }

  async function updateSchema(
    data: Partial<FormSchema> | Partial<FormSchema>[]
  ) {
    let updateData: Partial<FormSchema>[] = [];
    if (isObject(data)) {
      updateData.push(data as FormSchema);
    }
    if (isArray(data)) {
      updateData = [...data];
    }

    const hasField = updateData.every(
      (item) =>
        item.component === "ElDivider" ||
        (Reflect.has(item, "field") && item.field)
    );

    if (!hasField) {
      error(
        "All children of the form Schema array that need to be updated must contain the `field` field"
      );
      return;
    }
    const schema: FormSchema[] = [];
    updateData.forEach((item) => {
      unref(getSchema).forEach((val) => {
        if (val.field === item.field) {
          const newSchema = deepMerge(val, item);
          schema.push(newSchema as FormSchema);
        } else {
          schema.push(val);
        }
      });
    });
    _setDefaultValue(schema);

    schemaRef.value = uniqBy(schema, "field");
    console.log(schemaRef.value)
  }

  function _setDefaultValue(data: FormSchema | FormSchema[]) {
    let schemas: FormSchema[] = [];
    if (isObject(data)) {
      schemas.push(data as FormSchema);
    }
    if (isArray(data)) {
      schemas = [...data];
    }

    const obj: Recordable = {};
    schemas.forEach((item) => {
      if (
        item.component != "ElDivider" &&
        Reflect.has(item, "field") &&
        item.field &&
        !isNullOrUnDef(item.defaultValue)
      ) {
        obj[item.field] = item.defaultValue;
      }
    });
    setFieldsValue(obj);
  }

  return {
    getFieldsValue,
    setFieldsValue,
    resetSchema,
    validateField,
    resetFields,
    updateSchema,
    validate,
  };
}
